package com.ilxqx.framework.generator.core.mysql;

import com.google.common.collect.Lists;
import com.ilxqx.framework.generator.cast.CastToJavaType;
import com.ilxqx.framework.generator.constant.MysqlTableConstants;
import com.ilxqx.framework.generator.core.AbstractTableInfoParser;
import com.ilxqx.framework.generator.enumeration.ConstraintKeyEnum;
import com.ilxqx.framework.generator.key.impl.ConstraintKeyImpl;
import com.ilxqx.framework.generator.parser.TableField;
import com.ilxqx.framework.generator.parser.impl.TableFieldImpl;
import com.ilxqx.framework.generator.po.RawTableField;
import com.ilxqx.framework.generator.po.RawTableKey;
import org.apache.commons.lang3.StringUtils;

import java.util.List;

/**
 * mysql表信息解析类
 * @author venus
 */
public class MysqlTableInfoParser extends AbstractTableInfoParser {

    /**
     * java类型转化对象
     */
    private CastToJavaType toJavaType;

    public MysqlTableInfoParser(CastToJavaType toJavaType) {
        this.toJavaType = toJavaType;
    }

    /**
     * 解析表字段信息
     *
     * @param rawTableFields 原始表字段信息
     * @return 表字段List
     */
    @Override
    protected List<TableField> parseTableFieldsInfo(List<RawTableField> rawTableFields) {
        List<TableField> tableFields = Lists.newArrayListWithCapacity(16);
        for (RawTableField rawTableField : rawTableFields) {
            TableFieldImpl tableField = new TableFieldImpl();
            tableField.setFieldName(rawTableField.getName());
            tableField.setNullable(StringUtils.equals(rawTableField.getNullable(), MysqlTableConstants.NULL_STRING));
            tableField.setFieldComment(StringUtils.substringBefore(rawTableField.getComment(), "["));
            tableField.setFieldType(this.toJavaType.cast(rawTableField.getType()));
            tableField.setUnsigned(rawTableField.isUnsigned());
            tableField.setFieldSize(rawTableField.getSize());
            tableField.setRules(this.parseCommentRules(rawTableField.getComment()));

            tableFields.add(tableField);
        }
        return tableFields;
    }

    /**
     * 解析表键信息
     *  @param rawTableKeys 原始键信息
     * @param tableFields  表字段
     */
    @Override
    protected void parseTableKeysInfo(List<RawTableKey> rawTableKeys, List<TableField> tableFields) {
        for (RawTableKey rawTableKey : rawTableKeys) {
            if (rawTableKey.getSeq() == MysqlTableConstants.SEQ_IN_INDEX_FIRST) {
                ConstraintKeyImpl constraintKey = new ConstraintKeyImpl(rawTableKey.getKeyName(), awareKeyType(rawTableKey.getKeyName()));
                // 构建复合键，如果可能的话
                List<ConstraintKeyImpl.KeyMember> keyMembers = Lists.newArrayList();
                TableFieldImpl tableField = this.getTableField(rawTableKey.getFieldName(), tableFields);
                tableField.addKey(constraintKey);
                keyMembers.add(new ConstraintKeyImpl.KeyMemberImpl(tableField, rawTableKey.getSeq()));
                for (RawTableKey tableKey : rawTableKeys) {
                    if (tableKey.getKeyName().equals(rawTableKey.getKeyName())
                    && keyMembers.stream().noneMatch(keyMember -> StringUtils.equals(tableKey.getFieldName(), keyMember.getField().getName()))) {
                        // 添加
                        TableFieldImpl other = this.getTableField(tableKey.getFieldName(), tableFields);
                        other.addKey(constraintKey);
                        keyMembers.add(new ConstraintKeyImpl.KeyMemberImpl(other, tableKey.getSeq()));
                    }
                }
                // 添加进入限制键
                constraintKey.setKeyMembers(keyMembers);
            }
        }
    }

    private TableFieldImpl getTableField(String fieldName, List<TableField> tableFields) {
        return (TableFieldImpl) tableFields.stream().filter(tableField -> tableField.getName().equals(fieldName)).findFirst().orElse(null);
    }

    /**
     * 解析键类型
     * @param keyName 原始键名字符串
     * @return 键类型
     */
    private ConstraintKeyEnum awareKeyType(String keyName) {
        if (StringUtils.startsWith(keyName, MysqlTableConstants.PRIMARY_KEY_NAME_PREFIX)) {
            return ConstraintKeyEnum.PRIMARY_KEY;
        } else if (StringUtils.startsWith(keyName, MysqlTableConstants.UNIQUE_KEY_NAME_PREFIX)) {
            return ConstraintKeyEnum.UNIQUE_KEY;
        } else {
            return ConstraintKeyEnum.MULTIPLE_KEY;
        }
    }

}
